package edu.stanford.bmir.protege.web.client.ui.ontology.stkos.merger.option;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HasEnabled;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RadioButton;

import edu.stanford.bmir.protege.web.client.dispatch.DispatchServiceManager;
import edu.stanford.bmir.protege.web.client.project.Project;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.StkosUtilServiceManager;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.merger.CancelMergerResult;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.merger.MatchMode;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.merger.MergenceContent;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.merger.MergenceOptions;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.merger.MergenceResult;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.merger.actions.CancelMergerAction;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.merger.actions.MergeEntityAction;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.merger.actions.MergeEntityResult;
import edu.stanford.bmir.protege.web.client.ui.library.msgbox.MessageBox;
import edu.stanford.bmir.protege.web.client.ui.library.msgbox.YesNoHandler;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.GWTExtUtil;
import edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.interfaces.StkosCallBack;
import edu.stanford.bmir.protege.web.client.ui.projectmanager.DownloadProjectRequestHandler;
import edu.stanford.bmir.protege.web.client.ui.projectmanager.DownloadProjectRequestHandlerImpl;
import edu.stanford.bmir.protege.web.shared.project.GetAvailableProjectsAction;
import edu.stanford.bmir.protege.web.shared.project.GetAvailableProjectsResult;
import edu.stanford.bmir.protege.web.shared.project.ProjectDetails;

public class StkosMergerOptionView extends Composite implements HasEnabled {

	public enum StkosMergerOptionViewButtonType {

		AUTOMERGER("自动合并"),

		SINGLEMERGER("单条合并"),

		SHOWCLASSDESCRIPTION("显示类描述"),

		SHOWINDIVIDUAL("显示个体"),

		EXPORT("导出结果"),

		CANCEL("取消")

		;

		private String text;

		private StkosMergerOptionViewButtonType(String text) {
			this.text = text;
		}

		public String getButtonText() {
			return text;
		}
	}

	public enum StkosMergerOptionViewListBoxType {

		ACCORDINGPROJECT("参考本体")

		;

		private String text;

		private StkosMergerOptionViewListBoxType(String text) {
			this.text = text;
		}

		public String getButtonText() {
			return text;
		}
	}

	interface StkosMergerOptionViewUiBinder extends
			UiBinder<HTMLPanel, StkosMergerOptionView> {
	}

	private static StkosMergerOptionViewUiBinder ourUiBinder = GWT
			.create(StkosMergerOptionViewUiBinder.class);

	private Project project;

	private String entityName;

	private List<ProjectDetails> availableProjectDetails;

	private Map<StkosMergerOptionViewButtonType, StkosCallBack> btnHandlers = new HashMap<StkosMergerOptionViewButtonType, StkosCallBack>();

	private Map<StkosMergerOptionViewListBoxType, StkosCallBack> listBoxHandlers = new HashMap<StkosMergerOptionViewListBoxType, StkosCallBack>();

	/** 参考本体 */
	@UiField
	protected ListBox accordingProjects;

	// 匹配方式

	/** 映射结果 */
	@UiField
	protected RadioButton mapperResult;
	/** 精确匹配 */
	@UiField
	protected RadioButton exactMatching;
	/** 模糊匹配 */
	@UiField
	protected RadioButton fuzzyMatching;

	// 合并内容

	/** 合并属性 */
	@UiField
	protected CheckBox mergerProperty;
	/** 合并个体 */
	@UiField
	protected CheckBox mergerIndividual;
	/** 合并子类 */
	@UiField
	protected CheckBox mergerSubclass;

	// 按钮

	/** 自动合并 */
	@UiField
	protected Button btnAutoMerger;
	/** 单条合并 */
	@UiField
	protected Button btnSingleMerger;
	/** 显示类描述 */
	@UiField
	protected Button btnShowClassDescription;
	/** 显示个体 */
	@UiField
	protected Button btnShowIndividual;
	/** 导出结果 */
	@UiField
	protected Button btnExport;
	/** 取消 */
	@UiField
	protected Button btnCancel;

	public StkosMergerOptionView(Project project) {
		this.project = project;

		HTMLPanel rootElement = ourUiBinder.createAndBindUi(this);
		initWidget(rootElement);

		setAccordingProjectsItems();
		registerBtnEventHandlers();
		registerListBoxChangeEventHandlers();
	}

	@Override
	protected void onDetach() {
		super.onDetach();
		btnHandlers.clear();
		listBoxHandlers.clear();
	}

	@Override
	public boolean isEnabled() {
		return true;
	}

	@Override
	public void setEnabled(boolean enabled) {
		btnAutoMerger.setEnabled(enabled);
		btnSingleMerger.setEnabled(enabled);
		btnShowClassDescription.setEnabled(enabled);
		btnShowIndividual.setEnabled(enabled);
		btnExport.setEnabled(enabled);
		btnCancel.setEnabled(enabled);
	}

	public MergenceOptions getOptions() {
		MergenceOptions options = new MergenceOptions();
		ProjectDetails spd = getSelectedProjectDetails();
		if (spd != null && spd.getProjectId() != null) {
			options.setRefProjectName(spd.getProjectId().getId());
		}
		if (mapperResult.getValue()) {
			options.setMatchMode(MatchMode.MAPPING_RESULT);
		}
		if (exactMatching.getValue()) {
			options.setMatchMode(MatchMode.INCLUSIVE);
		}
		if (fuzzyMatching.getValue()) {
			options.setMatchMode(MatchMode.CASE_INSENSITIVE);
		}
		if (mergerProperty.getValue()) {
			options.getMergenceContentList().add(MergenceContent.PROPERTY);
		}
		if (mergerIndividual.getValue()) {
			options.getMergenceContentList().add(MergenceContent.INDIVIDUAL);
		}
		if (mergerSubclass.getValue()) {
			options.getMergenceContentList().add(MergenceContent.SUBCLASS);
		}
		return options;
	}

	public ProjectDetails getSelectedProjectDetails() {
		ProjectDetails selectedPd = null;
		if (accordingProjects.getSelectedIndex() != -1) {
			String selectedValue = accordingProjects.getValue(accordingProjects
					.getSelectedIndex());
			for (ProjectDetails pd : availableProjectDetails) {
				if (pd.getProjectId().getId().equals(selectedValue)) {
					selectedPd = pd;
					break;
				}
			}
		}
		return selectedPd;
	}

	protected void setAccordingProjectsItems() {
		availableProjectDetails = null;
		accordingProjects.clear();
		DispatchServiceManager.get().execute(new GetAvailableProjectsAction(),
				new AsyncCallback<GetAvailableProjectsResult>() {
					@Override
					public void onFailure(Throwable caught) {
						GWT.log("Loading project list error!", caught);
					}

					@Override
					public void onSuccess(GetAvailableProjectsResult result) {
						if (result == null || result.getDetails() == null
								|| result.getDetails().size() == 0) {
							GWT.log("Did not find any projects!");
						} else {
							availableProjectDetails = new ArrayList<ProjectDetails>();
							String pid = null;
							if (project != null
									&& project.getProjectId() != null) {
								pid = project.getProjectId().getId();
							}
							for (ProjectDetails pd : result.getDetails()) {
								try {
									if (!pd.isInTrash()
											&& !pd.getProjectId().getId()
													.equals(pid)) {
										availableProjectDetails.add(pd);
									}
								} catch (Exception e) {
								}
							}

							if (availableProjectDetails.size() > 0) {
								accordingProjects.addItem("请选择本体",
										GWTExtUtil.DEFAULTLISTBOXITEMVALUEID);
								for (ProjectDetails pd : availableProjectDetails) {
									try {
										accordingProjects.addItem(pd
												.getDisplayName(), pd
												.getProjectId().getId());
									} catch (Exception e) {
									}
								}
							}
						}
					}
				});
	}

	protected void registerListBoxChangeEventHandlers() {
		accordingProjects.addChangeHandler(new ChangeHandler() {
			@Override
			public void onChange(ChangeEvent event) {
				btnCancel.setEnabled(false);

				if (listBoxHandlers
						.get(StkosMergerOptionViewListBoxType.ACCORDINGPROJECT) != null) {
					listBoxHandlers.get(
							StkosMergerOptionViewListBoxType.ACCORDINGPROJECT)
							.onCallBack();
				}
			}
		});
	}

	protected void registerBtnEventHandlers() {
		ClickHandler clickHandler = new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				if (event.getSource().equals(btnAutoMerger)) {
					// GWTExtUtil.showProgressMonitor("自动合并", "程序处理中、请稍候...");
					autoMerger();
				} else if (event.getSource().equals(btnSingleMerger)) {
					// GWTExtUtil.showProgressMonitor("单条合并", "程序处理中、请稍候...");
					singleMerger();
				} else if (event.getSource().equals(btnShowClassDescription)) {
					showClassDescription();
				} else if (event.getSource().equals(btnShowIndividual)) {
					showIndividual();
				} else if (event.getSource().equals(btnExport)) {
					export();
				} else if (event.getSource().equals(btnCancel)) {
					cancel();
				}
			}
		};
		btnAutoMerger.addClickHandler(clickHandler);
		btnSingleMerger.addClickHandler(clickHandler);
		btnShowClassDescription.addClickHandler(clickHandler);
		btnShowIndividual.addClickHandler(clickHandler);
		btnExport.addClickHandler(clickHandler);
		btnCancel.addClickHandler(clickHandler);
	}

	protected void autoMerger() {
		String projectName = project.getProjectId().getId();
		MergenceOptions options = getOptions();
		if (options.getRefProjectName() == null
				|| "".equals(options.getRefProjectName().trim())) {
			MessageBox.showAlert("提示", "请选择一个参考本体!");
			return;
		}

		GWTExtUtil.showProgressMonitor("提示", "程序正在处理、请稍候...");

		AsyncCallback<MergenceResult> callback = new AsyncCallback<MergenceResult>() {
			@Override
			public void onFailure(Throwable caught) {
				MessageBox.showAlert("自动合并", "自动合并失败、详情：" + caught);
				doAutoMergerHandler(null);
			}

			@Override
			public void onSuccess(MergenceResult result) {
				if (result == null) {
					MessageBox.showAlert("自动合并", "自动合并返回结果为空！");
				}
				btnCancel.setEnabled(true);
				doAutoMergerHandler(result);
			}
		};
		StkosUtilServiceManager.getInstance().mergeOntology(projectName,
				options, callback);
	}

	protected void doAutoMergerHandler(MergenceResult result) {
		GWTExtUtil.hideProgressMonitor("提示", "程序处理完成!", 850);

		if (btnHandlers.get(StkosMergerOptionViewButtonType.AUTOMERGER) != null) {
			btnHandlers.get(StkosMergerOptionViewButtonType.AUTOMERGER)
					.onCallBack(result);
		}
	}

	protected void singleMerger() {
		if (this.entityName == null || "".equals(this.entityName.trim())) {
			MessageBox.showAlert("单条合并", "请在当前本体树中选中一条记录后、再使用此功能!");
			return;
		}
		MergenceOptions options = getOptions();
		if (options.getRefProjectName() == null
				|| "".equals(options.getRefProjectName().trim())) {
			MessageBox.showAlert("提示", "请选择一个参考本体!");
			return;
		}

		GWTExtUtil.showProgressMonitor("提示", "程序正在处理、请稍候...");

		String projectName = project.getProjectId().getId();
		MergeEntityAction action = new MergeEntityAction();
		action.setOptions(options);
		action.setEntityName(this.entityName);
		AsyncCallback<MergeEntityResult> callback = new AsyncCallback<MergeEntityResult>() {
			@Override
			public void onFailure(Throwable caught) {
				MessageBox.showAlert("单条合并", "单条合并处理失败、详情：" + caught);
				doSingleMergerHandler(null);
			}

			@Override
			public void onSuccess(MergeEntityResult result) {
				if (result == null) {
					MessageBox.showAlert("单条合并", "单条合并返回结果为空！");
				}
				// btnCancel.setEnabled(true);
				doSingleMergerHandler(result);
			}
		};
		StkosUtilServiceManager.getInstance().mergeEntity(projectName, action,
				callback);
	}

	protected void doSingleMergerHandler(MergeEntityResult result) {
		GWTExtUtil.hideProgressMonitor("提示", "程序处理完成!", 850);

		if (btnHandlers.get(StkosMergerOptionViewButtonType.SINGLEMERGER) != null) {
			btnHandlers.get(StkosMergerOptionViewButtonType.SINGLEMERGER)
					.onCallBack(result);
		}
	}

	protected void showClassDescription() {
		if (btnHandlers
				.get(StkosMergerOptionViewButtonType.SHOWCLASSDESCRIPTION) != null) {
			btnHandlers.get(
					StkosMergerOptionViewButtonType.SHOWCLASSDESCRIPTION)
					.onCallBack();
		}
	}

	protected void showIndividual() {
		if (btnHandlers.get(StkosMergerOptionViewButtonType.SHOWINDIVIDUAL) != null) {
			btnHandlers.get(StkosMergerOptionViewButtonType.SHOWINDIVIDUAL)
					.onCallBack();
		}
	}

	protected void export() {
		DownloadProjectRequestHandler downloadProjectRequestHandler = new DownloadProjectRequestHandlerImpl();
		downloadProjectRequestHandler.handleProjectDownloadRequest(project
				.getProjectId());
		doExportHandler();
	}

	protected void cancel() {
		final String projectName = project.getProjectId().getId();
		String refProjectName = null;
		try {
			refProjectName = getSelectedProjectDetails().getProjectId().getId();
		} catch (Exception e) {
		}
		final String rpn = refProjectName;
		YesNoHandler ynHandler = new YesNoHandler() {
			@Override
			public void handleYes() {
				cancelOperation(projectName, rpn);
			}

			@Override
			public void handleNo() {
			}
		};
		MessageBox.showYesNoConfirmBox("取消操作", "你确定要取消合并操作吗?", ynHandler);
	}

	protected void cancelOperation(String projectName, String refProjectName) {
		if (projectName == null || refProjectName == null) {
			MessageBox.showAlert("提示", "必要信息不完整,操作失败!");
			btnCancel.setEnabled(false);
			return;
		}

		GWTExtUtil.showProgressMonitor("提示", "程序正在处理、请稍候...");

		CancelMergerAction action = new CancelMergerAction();
		action.setRefProjectName(refProjectName);
		AsyncCallback<CancelMergerResult> callback = new AsyncCallback<CancelMergerResult>() {
			@Override
			public void onFailure(Throwable caught) {
				MessageBox.showAlert("取消操作", "取消操作处理失败、详情：" + caught);
				doCancelHandler(null);
			}

			@Override
			public void onSuccess(CancelMergerResult result) {
				doCancelHandler(result);
			}
		};
		StkosUtilServiceManager.getInstance().cancelMerger(projectName, action,
				callback);
	}

	protected void doCancelHandler(CancelMergerResult result) {
		GWTExtUtil.hideProgressMonitor("提示", "程序处理完成!", 1);

		if (result != null) {
			MessageBox.showMessage("取消合并操作成功", "共删除合并类" + result.getDelClass()
					+ "个,合并个体" + result.getDelIndividual() + "个,合并属性"+result.getDelProperty()+"个!");
		} else {
			MessageBox.showAlert("取消合并操作结束", "返回结果为空!");
		}
		btnCancel.setEnabled(false);

		if (btnHandlers.get(StkosMergerOptionViewButtonType.CANCEL) != null) {
			btnHandlers.get(StkosMergerOptionViewButtonType.CANCEL).onCallBack(
					result);
		}
	}

	protected void doExportHandler() {
		if (btnHandlers.get(StkosMergerOptionViewButtonType.EXPORT) != null) {
			btnHandlers.get(StkosMergerOptionViewButtonType.EXPORT)
					.onCallBack();
		}
	}

	public void setBtnHandler(StkosMergerOptionViewButtonType type,
			StkosCallBack cb) {
		if (type == null || cb == null) {
			return;
		}
		btnHandlers.remove(type);
		btnHandlers.put(type, cb);
	}

	public void setListBoxHandler(StkosMergerOptionViewListBoxType type,
			StkosCallBack cb) {
		if (type == null || cb == null) {
			return;
		}
		listBoxHandlers.remove(type);
		listBoxHandlers.put(type, cb);
	}

	protected void callAutoMergerHandler() {
		if (btnHandlers.get(StkosMergerOptionViewButtonType.AUTOMERGER) != null) {
			btnHandlers.get(StkosMergerOptionViewButtonType.AUTOMERGER)
					.onCallBack();
		}
	}

	public void setEntityName(String entityName) {
		this.entityName = entityName;
	}
}
